#include "xmethod.h"
#include "mymethods.h"
#include "func.h"
#include "funcx.h"
#include <vector>

#ifndef MYCALCULATE_H
#define MYCALCULATE_H


class CFi: public CFunc
{
public:
	CFuncX * f;
	vector<double> u;
	int i;
	int n;
	Piped p;
	Params params;
	vector<double> *min;
	list<vector<double> > *l;
public:
	CFi():min(0),l(0) {}
	~CFi() {}

	double operator ()(double x)
	{
		if (i < n - 1)
		{
			CFi fi(*this);
			fi.u[fi.i] = x;
			++(fi.i);
			CStrongin s;
			double xMin, yMin;
			s.operator()(&fi, p[fi.i].a, p[fi.i].b, xMin, yMin, params);
			return yMin;
		}
		else
		{
			u[i] = x;
			double res = f->operator()(u);

			//save experiments
			if (l != 0)
			{
				vector<double> temp(u.size() + 1);
				temp[0] = res;
				copy(u.begin(), u.end(), ++(temp.begin()));
				l->push_back(temp);
			}
			//find minimum
			if (min != 0)
			{
				if (res < (*min)[0])
				{
					(*min)[0] = res;
					copy(u.begin(), u.end(), ++(min->begin()));
				}
			}

			return res;
		}

		return 0.0;
	}
};

/*template <class T>*/ class CXCalculate
{
public:
	CXCalculate(void){}
	~CXCalculate(void){}
	void operator ()( CFuncX * f, Piped p, vector<double> &min, list<vector<double> > &listOfExperiments, Params params = paramDefault)
	{
		int n = p.size();
		CStrongin s;
		CFi fi;
		fi.f = f;
		fi.p = p;
		fi.i = 0;
		fi.n = n;
		fi.u.resize(fi.n);
		//copy Params
		fi.params = params;
//		fi.params.epsilon = params.epsilon;
//		fi.params.isAdaptiveConstLip = params.isAdaptiveConstLip;
//		fi.params.m = params.m;
//		fi.params.r = params.r;
//		fi.params.steps = params.steps;
		//end copy
		fi.l = &listOfExperiments;
		min.resize(n + 1, 1.0e1000);
		fi.min = &min;
		double xMin, yMin;
		s.operator()(&fi, p[fi.i].a, p[fi.i].b, xMin, yMin, params);

		return;
	}
};

#endif //MYCALCULATE_H
